# encoding:utf-8
from tornado.httpclient import AsyncHTTPClient
from tornado.httpclient import HTTPError
from tornado.gen import coroutine, Return
from tornado.escape import json_encode
from urllib import urlencode
from tornado.options import options

try:
    import json
except ImportError:
    import simplejson as json


class Client(object):
    _SUCCESS = ('created', 'updated', 'removed', 'set-quota',)
    _ERROR = ('already', 'not exist', 'error')

    def __init__(self, root_path=None, response_json=True):

        if not isinstance(root_path, str):
            root_path = options.ceph_api
            self.root_path = u'{0}/{1}'.format(root_path, 'api/v0.1')
        self.client = AsyncHTTPClient()
        if not hasattr(self, 'root_path'): self.root_path = root_path
        self.response_json = response_json

    def _request(self, **kwargs):
        headers_ = kwargs.get('headers')
        if not headers_:
            kwargs['headers'] = dict()
            headers_ = kwargs.get('headers')
        headers_['Accept'] = u'application/json'
        headers_['Content-Type'] = u'application/json'
        body = kwargs.get('prams')
        if body:
            kwargs['prams'] = urlencode(body)
        return kwargs

    def get(self, url, **kwargs):
        return self.fetch('GET', kwargs, url)

    def post(self, url, **kwargs):
        return self.fetch('POST', kwargs, url)

    def put(self, url, **kwargs):
        kwargs['body'] = b''
        return self.fetch('PUT', kwargs, url)

    def delete(self, url, **kwargs):
        return self.fetch('DELETE', kwargs, url)

    @coroutine
    def fetch(self, method, kwargs, url):

        kwargs = self._request(**kwargs)
        if len(self.root_path):
            url_request = u'{0}/{1}'.format(self.root_path, url, )
        else:
            url_request = url
        try:
            res = yield self.client.fetch(url_request, method=method, request_timeout=3, connect_timeout=3, **kwargs)
            if self.response_json:
                raise Return(self.get_json_response(res))
            else:
                raise Return(res.body)
        except HTTPError as e:
            raise Return({'status': "ERROR",
                          'output': 'HTTP error code:{0},meesage:{1},url:{2},method:{3}'.format(e.code, e.message, url,
                                                                                                method)})

    def get_json_response(self, res):
        body = json.loads(res.body)
        if isinstance(body,dict):
            if u'status' in body.keys():
                status = body.get('status')
                for success in self._SUCCESS:
                    if success in unicode(status):
                        body['status'] = 'OK'
                        body['output'] = status
                        return self.get_json(body)
                for err in self._ERROR:
                    if err in unicode(status):
                        body['status'] = 'ERROR'
                        body['output'] = status
                        return self.get_json(body)
                return self.get_json(body)
            else:
                return {'status':"OK",'output':''}
        else:
            return {'status':"ERROR",'output':'no response'}

    def get_json(self, body):
        body=json_encode(body)
        return json.loads(body)


class CephRestApi(Client):
    # 权限API
    def auth_list(self):
        return self.get(u'auth/list')

    def auth_get(self, entity):
        return self.get(u'auth/get?entity={0}'.format(entity))

    def auth_add(self, entity, caps={}):
        full_caps = list()
        if caps:
            for key in caps:
                permissions = caps[key].replace(' ', '+')
                full_caps.append(u'&caps={0}&caps={1}'.format(key, permissions))
        return self.put(u'auth/get-or-create?entity={0}{1}'.format(entity, ''.join(full_caps)), )

    def auth_del(self, entity):
        return self.put(u'auth/del?entity={0}'.format(entity))

    # 对象池管理
    def osd_lspools(self):
        return self.get(u'osd/lspools')

    def create_pool(self, poolname, ruleset=1, pgp_num=64, pg_num=64):
        return self.put(
            u'osd/pool/create?pool={0}&pgp_num={1}&pg_num={2}&ruleset={3}'.format(poolname, pgp_num, pg_num, ruleset))

    def delete_pool(self, poolname, sure=u'--yes-i-really-really-mean-it'):
        return self.put(u'osd/pool/delete?pool={0}&pool2={1}&sure={2}'.format(poolname, poolname, sure))

    def get_pool(self, poolname, prams=u'size'):
        return self.get(u'osd/pool/get?pool={0}&var={1}'.format(poolname, prams))

    def get_pool_stat(self, poolname):
        return self.get(u'osd/pool/stats?name={0}'.format(poolname))

    def get_pool_quota(self, poolname):
        return self.get(
            u'osd/pool/get-quota?pool={0}'.format(poolname))

    def set_pool(self, poolname, var, val):
        return self.put(
            u'osd/pool/set?pool={0}&var={1}&val={2}&force=--yes-i-really-mean-it'.format(poolname, var, val))

    def set_size_or_object_num_for_pool(self, poolname, field, val):
        return self.put(
            u'osd/pool/set-quota?pool={0}&field={1}&val={2}'.format(poolname, field, val))
